package com.bruce.pattern.creational.singleton;

import lombok.extern.slf4j.Slf4j;

/**
 * 双重检查 懒汉式单例模式,减少锁粒度
 *
 * Created by bruce on 2018/11/2 10:37
 */
@Slf4j
public class LazySingleton {

    // 如果反射攻击在方法在getInstance()方法之前调用是无法阻止反射攻击的
    private LazySingleton() {
        if (instance != null){
            throw new RuntimeException("单例构造器禁止反射");
        }
       log.info("LazySingleton is create");
    }

    //volatile
    //修饰的变量会在写操作的时候,将当前处理器缓存行的数据写回到系统内存,这个写操作会使其他cup中缓存行的数据无效,当其他cpu发现数据无效,会重新加载数据
    //1 得到内存中最新的对象引用,
    //2 防止重排序
    //如果发生指令重排寻,线程1获取了锁,还没有初始化完成,但是instance已经指向了内存地址,
    //线程2虽然无法获取锁,但是在最外层的if判断instance不为null,直接调用instance对象,而instance正在初始化,则会出现异常
    //因此使用volatile关键是必要的
    private static volatile LazySingleton instance;

    public static LazySingleton getInstance() {
        if (instance == null) {
            synchronized(LazySingleton.class){
                if(instance == null){
                    instance = new LazySingleton();
                    //对象的创建分为三个步骤
                    //1 分配内存给这个对象
                    //2 初始化对象
                    //3 设置instance指向刚分配的内存地址
                    //在这个过程中2和3的步骤可能互换,也就是虚拟机为了优化,进行指令的重排序
                    //所以 new 一个对象的过程不是原子操作
                }
            }
        }
        return instance;
    }




}
